////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2008, 2009 The Mist project                                  //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the implementation of the message classification functions/methods.
///

#include "messageinfo.hpp"

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include "common/assert.hpp"
#include "common/string.hpp"

////////////////////////////////////////////////////////////////////////////////
// Function Implementations                                                   //
////////////////////////////////////////////////////////////////////////////////

MessageInfo::MessageInfo() : _extraIndex(0) {
	/// Declare an error type with code \a code, message template \a message and location type \a type.
	///
	#define ERROR(code, message, type) _info[code] = Info(Error, string(message), type);
	
	/// Declare a warning type with code \a code, message template \a message and location type \a type.
	///
	#define WARNING(code, message, type) _info[code] = Info(Warning, string(message), type);
	
	ERROR( "unexpected character" , "Unexpected characters: %1%"                  , CompoundLocation )
	ERROR( "unterminated string"  , "Unterminated string literal."                , SingleLocation   )
	ERROR( "multiple definitions" , "Multiple definitions of symbol: %1%"         , MultipleLocation )
	ERROR( "missing"              , "Missing %1%"                                 , NoLocation       )
	ERROR( "missing at location"  , "Missing %1%"                                 , SingleLocation   )
	ERROR( "too many"             , "Too many %2%; expected %3%"                  , MultipleLocation )
	ERROR( "logical var init"     , "Logical variable `%1%' is being initialized" , SingleLocation   )
	ERROR( "ensurance body"       , "Function ensurance for `%2%' has a body"     , MultipleLocation )
	ERROR( "missing function"     , "Function `%1%' is missing"                   , NoLocation       )
	ERROR( "unexpected"           , "Unexpected %1%"                              , SingleLocation   )
	
	WARNING( "unterminated comment" , "Unterminated comment." , SingleLocation )
	
	#undef WARNING
	#undef ERROR
}

string MessageInfo::extra(const string& code, MessageSeverity severity, const string& message) {
	string newCode = code + ":" + to_string(_extraIndex++);
	_info[newCode] = Info(severity, message, SingleLocation);
	return newCode;
}

bool MessageInfo::code_exists(const string& code) const {
	return (_info.find(code) != _info.end());
}

MessageSeverity MessageInfo::severity(const string& code) const {
	It it = _info.find(code);
	
	assert(it != _info.end());
	
	return it->second.severity;
}

const string& MessageInfo::message(const string& code) const {
	It it = _info.find(code);
	
	assert(it != _info.end());
	
	return it->second.message;
}

MessageType MessageInfo::type(const string& code) const {
	It it = _info.find(code);
	
	assert(it != _info.end());
	
	return it->second.type;
}

string to_string(MessageSeverity severity) {
	switch(severity) {
		case Error:   return "error";
		case Warning: return "warning";
		default:      assert(false);
	}
}
